package org.example.supplychain.service;

import org.example.supplychain.domain.JdbcUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.sql.Date;
import java.time.LocalDate;
import java.time.Period;
import java.util.Map;

/**
 * BackupScheduleService 类用于管理数据备份和过期备份删除任务
 * 使用 Spring 框架的 @Scheduled 注解定时执行任务
 */
@Component
@EnableScheduling
public class BackupScheduleService {

    // 注入 JdbcUtils 组件，获取数据库信息
    @Autowired
    private JdbcUtils jdbcUtils;

    // 从配置文件中读取资源路径，用于存放备份文件
    @Value("${server.resource}")
    private String resourcePath;

    /**
     * 定时备份数据库信息
     * 使用 cron 表达式，每天 01:00 执行
     */
    @Scheduled(cron = "0 00 01 * * ?")
    public void scheduledBackUpDataBase() {
        backUpDataBase();
    }

    //以下可以被调用来实现手动备份
    public void backUpDataBase() {
        System.out.println("======执行定时器:定时备份数据库=======");

        // 构建备份文件夹路径，文件夹名称为当前日期
        String backUpPath = resourcePath + "/" + Date.valueOf(LocalDate.now());
        File backUpFile = new File(backUpPath);
        // 如果备份文件夹不存在，则创建
        if (!backUpFile.exists()) {
            backUpFile.mkdirs();
        }

        // 构建备份文件路径，文件名包含时间戳
        File dataFile = new File(backUpPath + "/supplychain" + System.currentTimeMillis() + ".sql");

        // 构建数据库备份命令
        StringBuffer sb = new StringBuffer();
        // 获取数据库连接信息
        Map<String, String> dbInfo = jdbcUtils.getDBInfo();
        // 构建 pg_dump 命令，用于备份 PostgreSQL 数据库
        /**sb.append("D:\\PostgreSQL\\bin\\pg_dump.exe");
        sb.append(" -U ").append(dbInfo.get("userName"));
        sb.append(" -d ").append(dbInfo.get("dbName"));
        sb.append(" -f ").append(dataFile.getAbsolutePath());**/

        // 构建 mysqldump 命令，用于备份 MySQL 数据库
        //注：此处最后写mysqldump命令的绝对地址
        sb.append("mysqldump");
        sb.append(" -h ").append(dbInfo.get("host"));
        sb.append(" -P").append(dbInfo.get("port"));
        sb.append(" -u").append(dbInfo.get("userName"));
        sb.append(" -p").append(dbInfo.get("passWord"));
        sb.append(" ").append(dbInfo.get("dbName"));
        sb.append(" -r ").append(dataFile.getAbsolutePath());

        System.out.println("======数据库备份cmd命令为：" + sb.toString() + "=======");

        try {
            // 使用 ProcessBuilder 执行命令
            ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", sb.toString());
            // 设置环境变量 PGPASSWORD，用于 pg_dump 认证
            //pb.environment().put("PGPASSWORD", dbInfo.get("passWord"));
            pb.redirectErrorStream(true);
            Process process = pb.start();
            int exitCode = process.waitFor();

            // 根据退出代码判断备份是否成功
            if (exitCode == 0) {
                System.out.println("======数据库备份成功，路径为：" + dataFile + "=======");
            } else {
                System.out.println("======数据库备份失败，错误代码：" + exitCode + "=======");
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            System.out.println("======数据库备份失败，异常为：" + e.getMessage() + "=======");
        }
    }

    /**
     * 定时删除数据库备份文件
     * 使用 cron 表达式，每天 01:10 执行
     */
    @Scheduled(cron = "0 10 01 * * ?")
    public void deleteBackUpDataBase() {
        System.out.println("======执行定时器:定时删除备份数据库文件=======");
        // 获取资源路径下的备份文件夹
        File backUpFile = new File(resourcePath);
        if (backUpFile.exists()) {
            // 列出资源路径下的所有文件夹
            File[] files = backUpFile.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        try {
                            // 尝试将文件夹名称解析为日期
                            LocalDate fileDate = LocalDate.parse(file.getName());
                            LocalDate currentDate = LocalDate.now();
                            // 计算文件夹日期与当前日期的间隔天数
                            Period period = Period.between(fileDate, currentDate);
                            long betweenDay = period.getDays();

                            // 如果文件夹日期超过7天，则删除该文件夹及其子文件
                            if (betweenDay > 7) {
                                File[] subFiles = file.listFiles();
                                if (subFiles != null) {
                                    for (File subFile : subFiles) {
                                        subFile.delete();
                                    }
                                }
                                file.delete();
                            }
                        } catch (Exception e) {
                            // 捕获异常，跳过无法解析为日期的文件夹
                            System.out.println("======跳过非法的文件夹：" + file.getName() + "=======");
                        }
                    }
                }
            }
        }
    }
}
